<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


namespace Celebrio\Logging;

use Nette;
use Nette\Object;
use Nette\Debug;
use Nette\Environment;

use Celebrio\FileSystem\Folder;
use Celebrio\FileSystem\File;
use Celebrio\FileSystem\TextFile;
use Celebrio\WindowsAzure\AzureStorage\AzureStorageBLOB;

use \Microsoft_WindowsAzure_Storage_Blob;
use \Microsoft_Http_Client_Adapter_Exception;
use \Microsoft_WindowsAzure_Exception;

/**
 * Description of LogHandling
 *
 * @author Robert
 */
class AzureLogHandling extends Object {
    private static $containerName = "logs-from-all-servers";
    private static $azureLogFileName = "azurePhpLogs.log";
    
    public static function initialize() {
        //creates container for logs and logging file
        try {
                    
            AzureStorageBLOB::connection()->createContainerIfNotExists(self::$containerName);
            
            //look into storage, if log file doesn't exist, create it
            $storedLog = AzureStorageBLOB::connection()->blobExists(self::$containerName, self::$azureLogFileName);
            if (!$storedLog) {
                //create log file in temp directory on local server
                $tempDir = Environment::expand("%tempDir%");
                $logFilePath = $tempDir . DIRECTORY_SEPARATOR . self::$azureLogFileName;
                new TextFile($logFilePath, "w");       

                //put log file into storage
                AzureStorageBLOB::connection()->putBlob(self::$containerName, self::$azureLogFileName, $logFilePath);        
            }
        } catch (\Exception $exception) {
            //TODO: try to create some better way to handle with exception at exception handler :)
        }
    }
    
    public static function getContainerName() {
        return self::$containerName;
    }
    
    public static function getAzureLogFileName() {
        return self::$azureLogFileName;
    }
    
    //TODO: If I understand it right, this method is being used to log an exception but the name doesn't suggest such action. I suggest a new name being something like logException(\Exception $exception)
    
    
    public static function azureStorageLogger(\Exception $exception) { 
        //if Debug::production mode == false -> do not create logs
        if(!Debug::$productionMode) {
            return;
        }
        
        try {          
            //create logging container
            AzureStorageBLOB::connection()->createContainerIfNotExists(self::$containerName);

            //prepare used variables
            $unformattedTime = time();
            $time = "[" . @date("d-M-Y H:i:s T", $unformattedTime) . "] "; //TODO:uses wrong timezone for some reason (maybe just in my computer)
            $hash = md5($exception);
        } catch(\Exception $exception) {
            //do nothing... try to create some better way to handle with exception at exception handler :)
        }

        //log exception on Azure storage into log file using lease for exclusive write accesss
        //if more servers try to get a lease on a logging blob, later one will wait and try again after a short delay,
        //this is repeated 5 times and then the server discards the log
        for ($i = 0; $i < 5; $i++) {
            try {
                $logLease = AzureStorageBLOB::connection()->leaseBlob(self::$containerName, self::$azureLogFileName, 'acquire'); //lease blob
                $blobData = AzureStorageBLOB::connection()->getBlobData(self::$containerName, self::$azureLogFileName, NULL, $logLease->LeaseId);
                $blobData .= $time . "PHP Fatal error:  Uncaught $exception\r\n";
                AzureStorageBLOB::connection()->putBlobData(self::$containerName, self::$azureLogFileName, $blobData, array(), $logLease->LeaseId);
                AzureStorageBLOB::connection()->leaseBlob(self::$containerName, self::$azureLogFileName, 'release', $logLease->LeaseId); //release blob               
                break;
            } catch (\Exception $exception) {
                usleep(100000); //sleep for 100 milliseconds
            } catch (Microsoft_WindowsAzure_Exception $exception) {
                usleep(100000); //sleep for 100 milliseconds
            }
        }

        try { 
            //path to logDir on local machine, log pages will be copied from here
            $sourceDirPath = Environment::expand("%logDir%");

            //check whether this exception is already logged in Azure storage, if not, try to log
            //trying to get all the names and compare hashes
            $storedException = false;
            $blobList = AzureStorageBLOB::connection()->listBlobs(self::$containerName, "exception");
            foreach ($blobList as $blob) {
                $name = $blob->Name;
                if(strpos($name, $hash)) {
                    $storedException = true;
                    break;
                }
            }   

            if(!$storedException) {
                $blobName = "exception ". @date("Y-m-d H-i-s ", $unformattedTime).  $hash . ".html";
                //check local log directory and find the correct error page to copy
                $sourceDir = new Folder($sourceDirPath);
                $dirContent = $sourceDir->getContent();
                $filePath = NULL;
                foreach($dirContent as $fileName) {
                    if (strpos($fileName, $hash)) {
                        $filePath = $sourceDirPath. DIRECTORY_SEPARATOR . $fileName;
                        break;
                    }
                }
                //copy the error page to Azure storage
                if (isset($filePath)) {
                    AzureStorageBLOB::connection()->putBlob(self::$containerName, $blobName, $filePath);
                }
            }
        } catch(\Exception $exception) {
            //do nothing... try to create some better way to handle with exception at exception handler :)
        }
    }
    
    
    
    
}
